package Rangel.firebrigade.world;

import Rangel.common.world.entity.RangelBuilding;
import org.uncommons.maths.number.NumberGenerator;
import org.uncommons.maths.random.GaussianGenerator;

public class Simulator {
    private RangelFireBrigadeWorld world;

    public static float GAMMA = 0.5f;
    public static float WATER_COEFFICIENT = 20f;

    private static final float CONSUME_COEFFICIENT_FOR_HUGE_MAP = 0.91f; // for huge map
    private static final float CONSUME_COEFFICIENT_FOR_NORMAL_MAP = 0.97f; // for others
    private static final float CONSUME_COEFFICIENT_FOR_CL = 0.85f; // for communication less
    private float RangelConsumeCoefficient;

    NumberGenerator<Double> burnRate;


    public Simulator(RangelFireBrigadeWorld world) {
        this.world = world;
        java.util.Random random = new java.util.Random((long) 23);
        burnRate = new GaussianGenerator(0.15, 0.02, random);
        double HUGE_MAP_MIN_SIZE = 650000;
        if (world.getBounds().getWidth() > HUGE_MAP_MIN_SIZE && world.getBounds().getHeight() > HUGE_MAP_MIN_SIZE) {
            RangelConsumeCoefficient = CONSUME_COEFFICIENT_FOR_HUGE_MAP;
        } else {
            RangelConsumeCoefficient = CONSUME_COEFFICIENT_FOR_NORMAL_MAP;
        }
        if (world.isCommunicationLess()) {
            RangelConsumeCoefficient *= CONSUME_COEFFICIENT_FOR_CL;
        }
    }

    public void update() {
        burn();
        cool();
    }

    private void burn() {
        double burnRate = this.burnRate.nextValue();
        for (RangelBuilding b : world.getRangelBuildings()) {
            if (b.getEstimatedTemperature() >= b.getIgnitionPoint() && b.getFuel() > 0.0f && b.isFlammable()) {
                float consumed = b.getConsume(burnRate) * RangelConsumeCoefficient;
                if (consumed > b.getFuel()) {
                    consumed = b.getFuel();
                }
                b.setEnergy(b.getEnergy() + consumed);
                b.setFuel(b.getFuel() - consumed);
            }
        }
    }

    private void cool() {
        for (RangelBuilding building : world.getRangelBuildings()) {
            waterCooling(building);
        }
    }

    private void waterCooling(RangelBuilding b) {
        double lWATER_COEFFICIENT = (b.getEstimatedFieryness() > 0 && b.getEstimatedFieryness() < 4 ? WATER_COEFFICIENT : WATER_COEFFICIENT * GAMMA);
        if (b.getWaterQuantity() > 0) {
            double dE = b.getEstimatedTemperature() * b.getCapacity();
            if (dE <= 0) {
                return;
            }
            double effect = b.getWaterQuantity() * lWATER_COEFFICIENT;
            int consumed = b.getWaterQuantity();
            if (effect > dE) {
                double pc = 1 - ((effect - dE) / effect);
                effect *= pc;
                consumed *= pc;
            }
            b.setWaterQuantity(b.getWaterQuantity() - consumed);
            b.setEnergy(b.getEnergy() - effect);
        }
    }
}
